#!/usr/bin/env python3
from pyVmomi import vim
from pyVim.connect import SmartConnect, Disconnect
import ssl
import getpass
import atexit
import requests
import os
import sys
import ipaddress


# ---------- debug ----------
print("=== env begin ===")
for k, v in os.environ.items():
    if k.startswith("JIANMU_"):
        print(f"{k}={v}")
print("=== env end ===")
# ---------------------------

try:
    ...
except Exception as e:
    print("❌ 异常:", e)
    traceback.print_exc()
    sys.exit(1)

def get_vm_info(content):
    vm_view = content.viewManager.CreateContainerView(
        content.rootFolder, [vim.VirtualMachine], True)
    return [
        {
            'name': vm.name,
            'ip': vm.guest.ipAddress if vm.guest and vm.guest.ipAddress else "N/A"
        }
        for vm in vm_view.view
    ]

def get_session(acl_url, username, password):
    login_url = f"{acl_url}/acl/login"
    session = requests.Session()
    resp = session.post(login_url, json={
        "username": username,
        "password": password
    })
    if resp.status_code != 200:
        raise Exception(f"登录失败，状态码: {resp.status_code}，响应: {resp.text}")
    print("🔐 登录成功")
    return session


def main():
    vc_host = os.environ.get("JIANMU_VC_HOST", "")
    vc_user = os.environ.get("JIANMU_VC_USER", "")
    vc_pass = os.environ.get("JIANMU_VC_PASS", "")
    api_url = os.environ.get("JIANMU_API_URL", "")
    acl_url = os.environ.get("JIANMU_ACL_URL", "")
    api_user = os.environ.get("JIANMU_API_USER", "")
    api_pass = os.environ.get("JIANMU_API_PASS", "")


    # 获取 vCenter 密码
    password = vc_pass or os.environ.get("VCENTER_PASSWORD")
    if not password:
        password = getpass.getpass(f"请输入 {vc_user} 的密码: ")

    try:
        # 创建不验证SSL的上下文
        context = ssl._create_unverified_context()

        # 连接 vCenter
        si = SmartConnect(
            host=vc_host,
            user=vc_user,
            pwd=password,
            sslContext=context
        )
        atexit.register(Disconnect, si)

        # 获取虚拟机信息
        vms = get_vm_info(si.RetrieveContent())
        vm_dict = {}
        for vm in vms:
            name = vm["name"]
            ip = vm["ip"]
            try:
                ipaddress.ip_address(ip)
                vm_dict[name] = ip
            except ValueError:
                print(f"⚠️ 忽略资产（IP 非法）: {name} -> {ip}")
        # 登录获取 token
        session = get_session(acl_url, api_user, api_pass)

        # 获取已有资产
        asset_url = f"{api_url}/oneterm/v1/asset?page_index=1&page_size=100"
        resp = session.get(asset_url)
        if resp.status_code != 200:
            raise Exception(f"获取资产列表失败，状态码: {resp.status_code}，响应: {resp.text}")

        # 根据实际接口返回格式提取资产
        data = resp.json()
        items = data.get("data", {}).get("list", []) or data.get("data", {}).get("items", [])

        exist_names = {item["name"]: item for item in items}

        # 创建新资产
        for name, ip in vm_dict.items():
            if name not in exist_names:
                try:
                    ipaddress.ip_address(ip)
                except ValueError:
                    print(f"⚠️ 忽略资产（IP 非法）: {name} -> {ip}")
                    continue

                print(f"🆕 创建资产: {name} -> {ip}")
                create_resp = session.post(f"{api_url}/oneterm/v1/asset", json={
                    "name": name,
                    "ip": ip,
                    "parent_id": 1,
                    "allow": True,
                    "cmd_ids": "",
                    "connectable": True,
                    "protocols": ["ssh:22"],
                    "authorization": {"1": [1]},
                    "comment": ""
                })
                if create_resp.status_code >= 300:
                    print(f"⚠️ 创建失败: {create_resp.status_code} - {create_resp.text}")
                if create_resp.status_code >= 300:
                    print(f"⚠️ 创建失败: {create_resp.status_code} - {create_resp.text}")

        # 删除旧资产

        # 重新拉取最新资产（包含新添加的）,确保删除所有离线资产
        asset_url = f"{api_url}/oneterm/v1/asset?page_index=1&page_size=100"
        latest_resp = session.get(asset_url)
        if latest_resp.status_code != 200:
            raise Exception(f"重新获取资产失败: {latest_resp.status_code} - {latest_resp.text}")

        latest_data = latest_resp.json()
        latest_items = latest_data.get("data", {}).get("list", []) or latest_data.get("data", {}).get("items", [])

        for item in latest_items:
            ip_in_oneterm = str(item.get("ip", "")).strip().lower()
            asset_id = item["id"]           
            # 判断并删除离线状态的资产
            if item.get("connectable") is False:
                delete_url = f"{api_url}/oneterm/v1/asset/{asset_id}"
                print(f"❌ 删除资产: {ip_in_oneterm} -> ID: {asset_id}")
                del_resp = session.delete(delete_url)
                if del_resp.status_code >= 300:
                    print(f"⚠️ 删除失败: {del_resp.status_code} - {del_resp.text}")
                else:
                    print(f"✅ 删除成功: {ip_in_oneterm}")
        print("✅ 同步完成")

    except Exception as e:
        print(f"❌ 错误: {str(e)}")
        sys.exit(1)

if __name__ == "__main__":
    main()